View Javadoc
1   package org.apache.maven.surefire.testng.conf;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *     http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import java.lang.reflect.Method;
23  import java.util.ArrayList;
24  import java.util.HashMap;
25  import java.util.Map;
26  
27  import org.apache.maven.surefire.booter.ProviderParameterNames;
28  import org.apache.maven.surefire.testset.TestSetFailedException;
29  import org.testng.TestNG;
30  import org.testng.xml.XmlSuite;
31  
32  /**
33   * TestNG configurator for 5.3+ versions. TestNG exposes a {@link org.testng.TestNG#configure(java.util.Map)} method.
34   * All suppported TestNG options are passed in String format, except
35   * <code>TestNGCommandLineArgs.LISTENER_COMMAND_OPT</code> which is <code>List&gt;Class&lt;</code>,
36   * <code>TestNGCommandLineArgs.JUNIT_DEF_OPT</code> which is a <code>Boolean</code>,
37   * <code>TestNGCommandLineArgs.SKIP_FAILED_INVOCATION_COUNT_OPT</code> which is a <code>Boolean</code>,
38   * <code>TestNGCommandLineArgs.OBJECT_FACTORY_COMMAND_OPT</code> which is a <code>Class</code>,
39   * <code>TestNGCommandLineArgs.REPORTERS_LIST</code> which is a <code>List&gt;ReporterConfig&lt;</code>.
40   * <p/>
41   * Test classes and/or suite files are not passed along as options parameters, but configured separately.
42   *
43   * @author <a href='mailto:the[dot]mindstorm[at]gmail[dot]com'>Alex Popescu</a>
44   */
45  public class TestNGMapConfigurator
46      implements Configurator
47  {
48      public void configure( TestNG testng, Map<String, String> options )
49          throws TestSetFailedException
50      {
51          Map convertedOptions = getConvertedOptions( options );
52          testng.configure( convertedOptions );
53      }
54  
55      public void configure( XmlSuite suite, Map<String, String> options )
56          throws TestSetFailedException
57      {
58          String threadCountString = options.get( ProviderParameterNames.THREADCOUNT_PROP );
59          int threadCount = ( null != threadCountString ) ? Integer.parseInt( threadCountString ) : 1;
60          suite.setThreadCount( threadCount );
61  
62          String parallel = options.get( ProviderParameterNames.PARALLEL_PROP );
63          if ( parallel != null )
64          {
65              suite.setParallel( parallel );
66          }
67      }
68  
69      Map<String, Object> getConvertedOptions( Map<String, String> options )
70          throws TestSetFailedException
71      {
72          Map<String, Object> convertedOptions = new HashMap<String, Object>();
73          convertedOptions.put( "-mixed", false );
74          for ( Map.Entry<String, String> entry : options.entrySet() )
75          {
76              String key = entry.getKey();
77              Object val = entry.getValue();
78              if ( "listener".equals( key ) )
79              {
80                  val = convertListeners( entry.getValue() );
81              }
82              else if ( "objectfactory".equals( key ) )
83              {
84                  val = AbstractDirectConfigurator.loadClass( entry.getValue() );
85              }
86              else if ( "testrunfactory".equals( key ) )
87              {
88                  val = AbstractDirectConfigurator.loadClass( entry.getValue() );
89              }
90              else if ( "reporter".equals( key ) )
91              {
92                  // for TestNG 5.6 or higher
93                  // TODO support multiple reporters?
94                  val = convertReporterConfig( val );
95                  key = "reporterslist";
96              }
97              else if ( "junit".equals( key ) )
98              {
99                  val = convert( val, Boolean.class );
100             }
101             else if ( "skipfailedinvocationcounts".equals( key ) )
102             {
103                 val = convert( val, Boolean.class );
104             }
105             else if ( "mixed".equals( key ) )
106             {
107                 val = convert( val, Boolean.class );
108             }
109             else if ( "configfailurepolicy".equals( key ) )
110             {
111                 val = convert( val, String.class );
112             }
113             else if ( "group-by-instances".equals( key ) )
114             {
115                 val = convert( val, Boolean.class );
116             }
117             else if ( ProviderParameterNames.THREADCOUNT_PROP.equals( key ) )
118             {
119                 val = convert ( val, String.class );
120             }
121             else if ( "suitethreadpoolsize".equals( key ) )
122             {
123                 // for TestNG 6.9.7 or higher
124                 val = convert( val, Integer.class );
125             }
126             else if ( "dataproviderthreadcount".equals( key ) )
127             {
128                 // for TestNG 5.10 or higher
129                 val = convert( val, Integer.class );
130             }
131 
132             if ( key.startsWith( "-" ) )
133             {
134                 convertedOptions.put( key, val );
135             }
136             else
137             {
138                 convertedOptions.put( "-" + key, val );
139             }
140         }
141         return convertedOptions;
142     }
143 
144     // ReporterConfig only became available in later versions of TestNG
145     protected Object convertReporterConfig( Object val )
146     {
147         final String reporterConfigClassName = "org.testng.ReporterConfig";
148         try
149         {
150             Class<?> reporterConfig = Class.forName( reporterConfigClassName );
151             Method deserialize = reporterConfig.getMethod( "deserialize", String.class );
152             Object rc = deserialize.invoke( null, val );
153             ArrayList<Object> reportersList = new ArrayList<Object>();
154             reportersList.add( rc );
155             return reportersList;
156         }
157         catch ( Exception e )
158         {
159             return val;
160         }
161     }
162 
163     protected Object convertListeners( String listenerClasses ) throws TestSetFailedException
164     {
165         return AbstractDirectConfigurator.loadListenerClasses( listenerClasses );
166     }
167 
168     protected Object convert( Object val, Class<?> type )
169     {
170         if ( val == null )
171         {
172             return null;
173         }
174         if ( type.isAssignableFrom( val.getClass() ) )
175         {
176             return val;
177         }
178 
179         if ( ( type == Boolean.class || type == boolean.class ) && val.getClass() == String.class )
180         {
181             return Boolean.valueOf( (String) val );
182         }
183 
184         if ( ( type == Integer.class || type == int.class ) && val.getClass() == String.class )
185         {
186             return Integer.valueOf( (String) val );
187         }
188 
189         if ( type == String.class )
190         {
191             return val.toString();
192         }
193 
194         return val;
195     }
196 }